/*
 * Author  : Leo <lipf160627@163.com>
 * Created : 2025-7-27
 * Desc    : 1.28 inch circle LCD driver
 */

#include "lcd.hpp"

#include <stdint.h>

#include <array>
#include <vector>

static spi_device_handle_t spi;

//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
#define PARALLEL_LINES 12

#define SPI_BUF_BYTE_MAX (LCD_WIDTH * PARALLEL_LINES * 2)

typedef struct {
    Lcd* instance;
    int  dc;
} SpiUserData;

Lcd::Lcd(spi_host_device_t spiHost, gpio_num_t pinClk, gpio_num_t pinMosi, gpio_num_t pinRst, gpio_num_t pinDc,
         gpio_num_t pinCs, gpio_num_t pinBlk)
         : m_spiHost(spiHost), m_pinClk(pinClk), m_pinMosi(pinMosi), m_pinRst(pinRst), m_pinDc(pinDc),
           m_pinCs(pinCs), m_pinBlk(pinBlk)
{
    gpio_config_t io_conf = {};
    io_conf.pin_bit_mask = ((1ULL << m_pinDc) | (1ULL << m_pinRst) | (1ULL << m_pinBlk));
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
    gpio_config(&io_conf);

    this->spiInit();

    this->init();
}

void Lcd::spiPreTransferCallback(spi_transaction_t *t)
{
    SpiUserData* userData = static_cast<SpiUserData*>(t->user);
    if (userData && userData->instance) {
        gpio_set_level(userData->instance->m_pinDc, userData->dc);
    }
}

void Lcd::spiInit()
{
    spi_bus_config_t buscfg {
        .mosi_io_num = this->m_pinMosi,
        .miso_io_num = -1,
        .sclk_io_num = this->m_pinClk,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        // .max_transfer_sz = PARALLEL_LINES * 320 * 2 + 8
        .max_transfer_sz = SPI_BUF_BYTE_MAX + 8
    };
    spi_device_interface_config_t devcfg {
        .mode = 0,                              //SPI mode 0 or 3
        .clock_speed_hz = 26 * 1000 * 1000,     //Clock out at 26 MHz
        .spics_io_num = this->m_pinCs,          //CS pin
        .queue_size = 7,                        //We want to be able to queue 7 transactions at a time
        .pre_cb = this->spiPreTransferCallback, //Specify pre-transfer callback to handle D/C line
    };
    //Initialize the SPI bus
    esp_err_t ret = spi_bus_initialize(this->m_spiHost, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret = spi_bus_add_device(this->m_spiHost, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
}

void Lcd::init()
{
    // Reset the display
    gpio_set_level(this->m_pinRst, 0);
    vTaskDelay(pdMS_TO_TICKS(100));
    gpio_set_level(this->m_pinRst, 1);
    vTaskDelay(pdMS_TO_TICKS(100));

    // Open back light
    gpio_set_level(this->m_pinBlk, 1);
    vTaskDelay(pdMS_TO_TICKS(100));

    this->writeCommand(0xEF);
    this->writeCommand(0xEB);
    this->writeData(0x14);
    
    this->writeCommand(0xFE);
    this->writeCommand(0xEF);

    this->writeCommand(0xEB);
    this->writeData(0x14);

    this->writeCommand(0x84);
    this->writeData(0x40);

    this->writeCommand(0x85);
    this->writeData(0xFF);

    this->writeCommand(0x86);
    this->writeData(0xFF);

    this->writeCommand(0x87);
    this->writeData(0xFF);

    this->writeCommand(0x88);
    this->writeData(0x0A);

    this->writeCommand(0x89);
    this->writeData(0x21);

    this->writeCommand(0x8A);
    this->writeData(0x00);

    this->writeCommand(0x8B);
    this->writeData(0x80);

    this->writeCommand(0x8C);
    this->writeData(0x01);

    this->writeCommand(0x8D);
    this->writeData(0x01);

    this->writeCommand(0x8E);
    this->writeData(0xFF);

    this->writeCommand(0x8F);
    this->writeData(0xFF);

    this->writeCommand(0xB6);
    this->writeData((const uint8_t[]){0x00, 0x20}, 2);

    this->writeCommand(0x36);
    if(USE_HORIZONTAL==0)this->writeData(0x08);
    else if(USE_HORIZONTAL==1)this->writeData(0xC8);
    else if(USE_HORIZONTAL==2)this->writeData(0x68);
    else this->writeData(0xA8);

    this->writeCommand(0x3A);
    this->writeData(0x05);

    this->writeCommand(0x90);
    this->writeData((const uint8_t[]){0x08, 0x08, 0x08, 0x08}, 4);

    this->writeCommand(0xBD);
    this->writeData(0x06);
    
    this->writeCommand(0xBC);
    this->writeData(0x00);

    this->writeCommand(0xFF);
    this->writeData((const uint8_t[]){0x60, 0x01, 0x04}, 3);

    this->writeCommand(0xC3);
    this->writeData(0x13);
    this->writeCommand(0xC4);
    this->writeData(0x13);

    this->writeCommand(0xC9);
    this->writeData(0x22);

    this->writeCommand(0xBE);
    this->writeData(0x11);

    this->writeCommand(0xE1);
    this->writeData((const uint8_t[]){0x10, 0x0E}, 2);

    this->writeCommand(0xDF);
    this->writeData((const uint8_t[]){0x21, 0x0C, 0x02}, 3);

    this->writeCommand(0xF0);
    this->writeData((const uint8_t[]){0x45, 0x09, 0x08, 0x08, 0x26, 0x2A}, 6);

    this->writeCommand(0xF1);
    this->writeData((const uint8_t[]){0x43, 0x70, 0x72, 0x36, 0x37, 0x6F}, 6);

    this->writeCommand(0xF2);
    this->writeData((const uint8_t[]){0x45, 0x09, 0x08, 0x08, 0x26, 0x2A}, 6);

    this->writeCommand(0xF3);
    this->writeData((const uint8_t[]){0x43, 0x70, 0x72, 0x36, 0x37, 0x6F}, 6);

    this->writeCommand(0xED);
    this->writeData((const uint8_t[]){0x1B, 0x0B}, 2);

    this->writeCommand(0xAE);
    this->writeData(0x77);

    this->writeCommand(0xCD);
    this->writeData(0x63);

    this->writeCommand(0x70);
    this->writeData((const uint8_t[]){0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03}, 9);

    this->writeCommand(0xE8);
    this->writeData(0x34);

    this->writeCommand(0x62);
    this->writeData((const uint8_t[]){0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70}, 12);

    this->writeCommand(0x63);
    this->writeData((const uint8_t[]){0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70}, 12);

    this->writeCommand(0x64);
    this->writeData((const uint8_t[]){0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07}, 7);

    this->writeCommand(0x66);
    this->writeData((const uint8_t[]){0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00}, 10);

    this->writeCommand(0x67);
    this->writeData((const uint8_t[]){0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98}, 10);

    this->writeCommand(0x74);
    this->writeData((const uint8_t[]){0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00}, 7);
    
    this->writeCommand(0x98);
    this->writeData((const uint8_t[]){0x3E, 0x07}, 2);

    this->writeCommand(0x35);
    this->writeCommand(0x21);

    this->writeCommand(0x11);
    vTaskDelay(pdMS_TO_TICKS(120));
    this->writeCommand(0x29);
    vTaskDelay(pdMS_TO_TICKS(20));

    this->fill(0, 0, 240, 240, WHITE);
}

void Lcd::setAddress(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
    this->writeCommand(0x2A);//列地址设置

    // 此处发送地址时，不能使用uint16_t，否则会出错
    uint8_t addrX[] = {
        static_cast<uint8_t>(x1 >> 8),
        static_cast<uint8_t>(x1 & 0xFF),
        static_cast<uint8_t>(x2 >> 8),
        static_cast<uint8_t>(x2 & 0xFF)
    };
    this->writeData(addrX, 4);

    this->writeCommand(0x2B);//行地址设置

    uint8_t addrY[] = {
        static_cast<uint8_t>(y1 >> 8),
        static_cast<uint8_t>(y1 & 0xFF),
        static_cast<uint8_t>(y2 >> 8),
        static_cast<uint8_t>(y2 & 0xFF)
    };
    this->writeData(addrY, 4);

    this->writeCommand(0x2C);//储存器写
}

void Lcd::writeCommand(uint8_t cmd)
{
    SpiUserData userData = {
        .instance = this,
        .dc = 0                     //D/C needs to be set to 0
    };

    spi_transaction_t t = {};
    t.length    = 8;                //Command is 8 bits
    t.tx_buffer = &cmd;             //The data is the cmd itself
    t.user      = (void*)&userData;

    esp_err_t ret = spi_device_polling_transmit(spi, &t); //Transmit!
    assert(ret == ESP_OK);          //Should have had no issues.
}

void Lcd::writeData(const uint8_t data)
{
    this->writeData(&data, 1);
}

void Lcd::writeData(const uint8_t *data, size_t len)
{
    if (len == 0) {
        return;    //no need to send anything
    }

    SpiUserData userData = {
        .instance = this,
        .dc = 1                     //D/C needs to be set to 1
    };

    spi_transaction_t t = {};
    t.length    = len * 8;          //Len is in bytes, transaction length is in bits.
    t.tx_buffer = data;             //Data
    t.user      = (void*)&userData;

    esp_err_t ret = spi_device_polling_transmit(spi, &t); //Transmit!
    assert(ret == ESP_OK);          //Should have had no issues.
}

uint8_t Lcd::getSizeYFromFontSize(Lcd_FontSize_t size)
{
    switch (size) {
    case FONT_1206:
        return 12;
    case FONT_1608:
        return 16;
    case FONT_2412:
        return 24;
    case FONT_3216:
        return 32;
    default:
        return 0;
    }
}

void Lcd::fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{
    this->setAddress(xsta, ysta, xend - 1, yend - 1);//设置显示范围

    int width  = xend - xsta;
    int height = yend - ysta;

    uint8_t colorHighByte = static_cast<uint8_t>(color >> 8);
    uint8_t colorLowByte  = static_cast<uint8_t>(color & 0xFF);

    std::vector<uint8_t> buffer(width * 2);
    for (int i = 0; i < width; i++) {
        buffer[2 * i]     = colorHighByte;
        buffer[2 * i + 1] = colorLowByte;
    }

    for (int i = 0; i < height; i++) {
        this->writeData(buffer.data(), buffer.size());
    }
}

void Lcd::drawPoint(uint16_t x, uint16_t y, uint16_t color)
{
    this->setAddress(x, y, x, y);//设置光标位置

    uint8_t data[] = {static_cast<uint8_t>(color >> 8), static_cast<uint8_t>(color)};
    this->writeData(data, 2);
}

void Lcd::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    uint16_t t;
    int xerr=0, yerr=0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;
    delta_x=x2-x1; //计算坐标增量
    delta_y=y2-y1;
    uRow=x1;//画线起点坐标
    uCol=y1;
    if(delta_x>0)incx=1; //设置单步方向
    else if (delta_x==0)incx=0;//垂直线
    else {incx=-1;delta_x=-delta_x;}
    if(delta_y>0)incy=1;
    else if (delta_y==0)incy=0;//水平线
    else {incy=-1;delta_y=-delta_y;}
    if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
    else distance=delta_y;
    for(t=0;t<distance+1;t++)
    {
        this->drawPoint(uRow, uCol, color);//画点
        xerr+=delta_x;
        yerr+=delta_y;
        if(xerr>distance)
        {
            xerr-=distance;
            uRow+=incx;
        }
        if(yerr>distance)
        {
            yerr-=distance;
            uCol+=incy;
        }
    }
}

void Lcd::drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    this->drawLine(x1, y1, x2, y1, color);
    this->drawLine(x1, y1, x1, y2, color);
    this->drawLine(x1, y2, x2, y2, color);
    this->drawLine(x2, y1, x2, y2, color);
}

void Lcd::drawCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
    int a, b;
    a=0;b=r;
    while(a<=b)
    {
        this->drawPoint(x0-b, y0-a, color); //3
        this->drawPoint(x0+b, y0-a, color); //0
        this->drawPoint(x0-a, y0+b, color); //1
        this->drawPoint(x0-a, y0-b, color); //2
        this->drawPoint(x0+b, y0+a, color); //4
        this->drawPoint(x0+a, y0-b, color); //5
        this->drawPoint(x0+a, y0+b, color); //6 
        this->drawPoint(x0-b, y0+a, color); //7
        a++;
        if((a*a+b*b)>(r*r))//判断要画的点是否过远
        {
            b--;
        }
    }
}

void Lcd::showChar(uint16_t x, uint16_t y, char num, uint16_t fc, uint16_t bc, Lcd_FontSize_t size, uint8_t mode)
{
    uint8_t sizey = this->getSizeYFromFontSize(size);

    uint8_t temp, sizex, t, m=0;
    uint16_t i, TypefaceNum;//一个字符所占字节大小
    uint16_t x0 = x;
    sizex = sizey / 2;
    TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * sizey;
    uint8_t num_pos = num - ' ';    //得到偏移后的值

    // uint16_t data[sizex * sizey];
    uint8_t* data = static_cast<uint8_t*>(heap_caps_malloc(sizex * sizey * sizeof(uint8_t) * 2, MALLOC_CAP_DMA));
    int pos = 0;

    this->setAddress(x, y, x + sizex - 1, y + sizey - 1);  //设置光标位置
    for (i = 0; i < TypefaceNum; i++)
    {
        if (sizey == 12) temp = ascii_1206[num_pos][i];              //调用6x12字体
        else if (sizey == 16) temp = ascii_1608[num_pos][i];         //调用8x16字体
        else if (sizey == 24) temp = ascii_2412[num_pos][i];         //调用12x24字体
        else if (sizey == 32) temp = ascii_3216[num_pos][i];         //调用16x32字体
        else return;
        for (t = 0; t < 8; t++)
        {
            if (!mode)//非叠加模式
            {
                if (temp & (0x01 << t)) {
                    data[pos++] = (uint8_t)(fc >> 8);
                    data[pos++] = (uint8_t)fc;
                }
                else {
                    data[pos++] = (uint8_t)(bc >> 8);
                    data[pos++] = (uint8_t)bc;
                }

                m++;
                if (m % sizex==0)
                {
                    m = 0;
                    break;
                }
            }
            else//叠加模式
            {
                printf("%s[%d]: mode != 0\n", __func__, __LINE__);
                if (temp & (0x01 << t)) this->drawPoint(x, y, fc);//画一个点
                x++;
                if ((x - x0) == sizex)
                {
                    x = x0;
                    y++;
                    break;
                }
            }
        }
    }

    if (!mode && pos) {
        this->writeData(data, pos);
        // printf("%s[%d]: size = %d, pos = %d, [%4x, %4x, %4x]\n", __func__, __LINE__, sizex * sizey, pos, data[0], data[1], data[2]);
    }

    free(data);
}

void Lcd::showString(uint16_t x, uint16_t y, const std::string& s, uint16_t fc, uint16_t bc, Lcd_FontSize_t size, uint8_t mode)
{
    if (s.empty()) return;

    uint8_t sizey = this->getSizeYFromFontSize(size);

    for (char c : s) {
        this->showChar(x, y, c, fc, bc, size, mode);
        x += sizey / 2;
    }

    // while (*p != '\0')
    // {
    //     this->showChar(x, y, *p, fc, bc, size, mode);
    //     x += sizey/2;
    //     p++;
    // }
}

uint32_t mypow(uint8_t m, uint8_t n)
{
    uint32_t result=1;
    while(n--)result*=m;
    return result;
}

void Lcd::showIntNum(uint16_t x, uint16_t y, uint16_t num, uint8_t len, uint16_t fc, uint16_t bc, Lcd_FontSize_t size)
{
    uint8_t sizey = this->getSizeYFromFontSize(size);

    uint8_t t, temp;
    uint8_t enshow = 0;
    uint8_t sizex = sizey / 2;
    for(t = 0; t < len; t++)
    {
        temp = (num / mypow(10, len - t - 1)) % 10;
        if (enshow == 0 && t < (len - 1))
        {
            if (temp == 0)
            {
                this->showChar(x + t * sizex, y, ' ', fc, bc, size, 0);
                continue;
            } else enshow = 1;
        }
        // printf("%s[%d]: %d\n", __func__, __LINE__, temp);
        this->showChar(x + t * sizex, y, temp + 48, fc, bc, size, 0);
    }
}

void Lcd::showFloatNum1(uint16_t x, uint16_t y, float num, uint8_t len, uint16_t fc, uint16_t bc, Lcd_FontSize_t size)
{
    uint8_t sizey = this->getSizeYFromFontSize(size);

    uint8_t t, temp, sizex;
    uint16_t num1;
    sizex=sizey/2;
    num1=num*100;
    for(t=0;t<len;t++)
    {
        temp=(num1/mypow(10, len-t-1))%10;
        if(t==(len-2))
        {
            this->showChar(x+(len-2)*sizex, y, '.', fc, bc, size, 0);
            t++;
            len+=1;
        }
        this->showChar(x+t*sizex, y, temp+48, fc, bc, size, 0);
    }
}

void Lcd::showPicture(uint16_t x, uint16_t y, uint16_t height, uint16_t width, const uint8_t pic[])
{
    this->setAddress(x, y, x + height - 1, y + width - 1);

    int total_pixels = height * width;
    int total_bytes  = total_pixels << 1;

    if (total_bytes <= SPI_BUF_BYTE_MAX) {
        this->writeData(pic, total_bytes);
    } else {
        int pos          = 0;
        int remainderLen = total_bytes % SPI_BUF_BYTE_MAX;

        for (int i = 0; i / SPI_BUF_BYTE_MAX; i++) {
            this->writeData(&pic[pos], SPI_BUF_BYTE_MAX);
            pos += SPI_BUF_BYTE_MAX;
        }

        if (remainderLen) {
            this->writeData(&pic[pos], remainderLen);
        }
    }
}

void Lcd::showChinese(uint16_t x, uint16_t y, char* s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    while(*s!=0)
    {
        if(sizey==12) this->showChinese12x12(x, y, s, fc, bc, sizey, mode);
        else if(sizey==16) this->showChinese16x16(x, y, s, fc, bc, sizey, mode);
        else if(sizey==24) this->showChinese24x24(x, y, s, fc, bc, sizey, mode);
        else if(sizey==32) this->showChinese32x32(x, y, s, fc, bc, sizey, mode);
        else return;
        s+=2;
        x+=sizey;
    }
}

void Lcd::showChinese12x12(uint16_t x, uint16_t y, char *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m=0;
    uint16_t k;
    uint16_t HZnum;//汉字数目
    uint16_t TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    TypefaceNum = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;

    HZnum=sizeof(tfont12)/sizeof(typFNT_GB12);    //统计汉字数目

    for(k=0;k<HZnum;k++)
    {
        if((tfont12[k].Index[0]==*(s))&&(tfont12[k].Index[1]==*(s+1)))
        {     
            this->setAddress(x, y, x+sizey-1, y+sizey-1);
            for(i=0;i<TypefaceNum;i++)
            {
                for(j=0;j<8;j++)
                {    
                    if(!mode)//非叠加方式
                    {
                        if (tfont12[k].Msk[i] & (0x01 << j)) {
                            uint8_t data[] = {static_cast<uint8_t>(fc >> 8), static_cast<uint8_t>(fc)};
                            this->writeData(data, 2);
                        } else {
                            uint8_t data[] = {static_cast<uint8_t>(bc >> 8), static_cast<uint8_t>(bc)};
                            this->writeData(data, 2);
                        }
                        m++;
                        if(m%sizey==0)
                        {
                            m=0;
                            break;
                        }
                    }
                    else//叠加方式
                    {
                        if(tfont12[k].Msk[i]&(0x01<<j))    this->drawPoint(x, y, fc);//画一个点
                        x++;
                        if((x-x0)==sizey)
                        {
                            x=x0;
                            y++;
                            break;
                        }
                    }
                }
            }
        }
        continue;  //查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响
    }
}

void Lcd::showChinese16x16(uint16_t x, uint16_t y, char *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m=0;
    uint16_t k;
    uint16_t HZnum;//汉字数目
    uint16_t TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);    //统计汉字数目
    for(k=0;k<HZnum;k++) 
    {
        if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
        {     
            this->setAddress(x, y, x+sizey-1, y+sizey-1);
            for(i=0;i<TypefaceNum;i++)
            {
                for(j=0;j<8;j++)
                {    
                    if(!mode)//非叠加方式
                    {
                        if (tfont16[k].Msk[i] & (0x01 << j)) {
                            uint8_t data[] = {static_cast<uint8_t>(fc >> 8), static_cast<uint8_t>(fc)};
                            this->writeData(data, 2);
                        } else {
                            uint8_t data[] = {static_cast<uint8_t>(bc >> 8), static_cast<uint8_t>(bc)};
                            this->writeData(data, 2);
                        }
                        m++;
                        if(m%sizey==0)
                        {
                            m=0;
                            break;
                        }
                    }
                    else//叠加方式
                    {
                        if(tfont16[k].Msk[i]&(0x01<<j))    this->drawPoint(x, y, fc);//画一个点
                        x++;
                        if((x-x0)==sizey)
                        {
                            x=x0;
                            y++;
                            break;
                        }
                    }
                }
            }
        }
        continue;  //查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响
    }
}

void Lcd::showChinese24x24(uint16_t x, uint16_t y, char *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m=0;
    uint16_t k;
    uint16_t HZnum;//汉字数目
    uint16_t TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);    //统计汉字数目
    for(k=0;k<HZnum;k++)
    {
        if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
        {     
            this->setAddress(x, y, x+sizey-1, y+sizey-1);
            for(i=0;i<TypefaceNum;i++)
            {
                for(j=0;j<8;j++)
                {    
                    if(!mode)//非叠加方式
                    {
                        if (tfont24[k].Msk[i] & (0x01 << j)) {
                            uint8_t data[] = {static_cast<uint8_t>(fc >> 8), static_cast<uint8_t>(fc)};
                            this->writeData(data, 2);
                        } else {
                            uint8_t data[] = {static_cast<uint8_t>(bc >> 8), static_cast<uint8_t>(bc)};
                            this->writeData(data, 2);
                        }
                        m++;
                        if(m%sizey==0)
                        {
                            m=0;
                            break;
                        }
                    }
                    else//叠加方式
                    {
                        if(tfont24[k].Msk[i]&(0x01<<j))    this->drawPoint(x, y, fc);//画一个点
                        x++;
                        if((x-x0)==sizey)
                        {
                            x=x0;
                            y++;
                            break;
                        }
                    }
                }
            }
        }
        continue;  //查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响
    }
}

void Lcd::showChinese32x32(uint16_t x, uint16_t y, char *s, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint8_t i, j, m=0;
    uint16_t k;
    uint16_t HZnum;//汉字数目
    uint16_t TypefaceNum;//一个字符所占字节大小
    uint16_t x0=x;
    TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    HZnum=sizeof(tfont32)/sizeof(typFNT_GB32);    //统计汉字数目
    for(k=0;k<HZnum;k++) 
    {
        if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1)))
        {     
            this->setAddress(x, y, x+sizey-1, y+sizey-1);
            for(i=0;i<TypefaceNum;i++)
            {
                for(j=0;j<8;j++)
                {    
                    if(!mode)//非叠加方式
                    {
                        if (tfont32[k].Msk[i] & (0x01 << j)) {
                            uint8_t data[] = {static_cast<uint8_t>(fc >> 8), static_cast<uint8_t>(fc)};
                            this->writeData(data, 2);
                        } else {
                            uint8_t data[] = {static_cast<uint8_t>(bc >> 8), static_cast<uint8_t>(bc)};
                            this->writeData(data, 2);
                        }
                        m++;
                        if(m%sizey==0)
                        {
                            m=0;
                            break;
                        }
                    }
                    else//叠加方式
                    {
                        if(tfont32[k].Msk[i]&(0x01<<j))    this->drawPoint(x, y, fc);//画一个点
                        x++;
                        if((x-x0)==sizey)
                        {
                            x=x0;
                            y++;
                            break;
                        }
                    }
                }
            }
        }
        continue;  //查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响
    }
}
